'''
Created on Oct 23, 2009

@author: Elena Erbiceanu, Greg Tener

Class definition for the genetic algorithm.
'''

import random 

from Individual import Individual 

class GA:
	'''
	Generic implementation for a genetic algorithm.
	'''

	def __init__(self):
		'''
		Constructor
		'''
		
		'Seeding the randomness of Greg\'s thoughts'
		self.seed = 42
		random.seed(self.seed)
		
		'Variables governing the runtime behavior of the GA'
		self.evaluator = None # to calculate fitness
		
		self.crossover = None
		self.mutate = None
		
		self.population_initializer = None
		self.parents_selector = None		
		self.merge_offspring = None
		
		'Generation specific variables'
		self.population = []
		self.generation = 0
			
		
		
	def terminate(self):
		' @todo Make this more generic. '
		if (self.generation >= 10):
			print('Ending evolution...')
			return True
		
		return False
	
	def generate_offspring(self, parents):
		offspring = []
		for couple in parents:
			child = self.crossover(couple[0], couple[1])
			offspring.append(self.mutate(child))
			
		return offspring
				
		
	def run(self):
		' Initialize population and evaluate. '
		self.population = self.population_initializer(self.population_size)
		
		for dude in self.population:
			self.evaluator.evaluate(dude)
		
		while (not self.terminate()):
			' Select parents. '
			parents = self.parents_selector(self.population)
			
			' Generate children. '
			children = self.generate_offspring(parents)
			
			' Evaluate fitness of children. '
			for child in children:
				self.evaluator.evaluate(child) 
				
			' Merge children with rest of population. '
			self.population = self.merge_offspring(self.population, children)
			' Go to next generation. '  
			self.generation += 1
			print('Generation: %d' % (self.generation))
			for dude in self.population:
				print(dude)				
			
		print('Evolution ended.')
